package com.navi.utils.sm2;

import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.math.ec.ECPoint;

import java.io.IOException;
import java.math.BigInteger;
/**
 * @Author: ZamXie
 * @Description:
 * @Date: Create in 16:00 2021/9/24
 * @Version 1.0
 */
public class SM2Utils {
    //生成随机秘钥对
    public static SM2KeyPair generateKeyPair(){
        SM2 sm2 =SM2.Instance();
        AsymmetricCipherKeyPair key = sm2.ecc_key_pair_generator.generateKeyPair();
        ECPrivateKeyParameters ecpriv = (ECPrivateKeyParameters) key.getPrivate();
        ECPublicKeyParameters ecpub = (ECPublicKeyParameters) key.getPublic();
        BigInteger privateKey = ecpriv.getD();
        ECPoint publicKey = ecpub.getQ();
//        System.out.println("公钥: " + Util.byteToHex(publicKey.getEncoded()));
//        System.out.println("私钥: " + Util.byteToHex(privateKey.toByteArray()));
        return  new SM2KeyPair(Util.byteToHex(publicKey.getEncoded()),Util.byteToHex(privateKey.toByteArray()));
    }



    //数据加密
    public static String encrypt(byte[] publicKey, byte[] data) throws IOException
    {
        if (publicKey == null || publicKey.length == 0)
        {
            return null;
        }

        if (data == null || data.length == 0)
        {
            return null;
        }

        byte[] source = new byte[data.length];
        System.arraycopy(data, 0, source, 0, data.length);

        Cipher cipher = new Cipher();
        SM2 sm2 = SM2.Instance();
        ECPoint userKey = sm2.ecc_curve.decodePoint(publicKey);

        ECPoint c1 = cipher.Init_enc(sm2, userKey);
        cipher.Encrypt(source);
        byte[] c3 = new byte[32];
        cipher.Dofinal(c3);

//      System.out.println("C1 " + Util.byteToHex(c1.getEncoded()));
//      System.out.println("C2 " + Util.byteToHex(source));
//      System.out.println("C3 " + Util.byteToHex(c3));
        //C1 C2 C3拼装成加密字串
        return Util.byteToHex(c1.getEncoded()) + Util.byteToHex(source) + Util.byteToHex(c3);

    }

    //数据解密
    public static byte[] decrypt(byte[] privateKey, byte[] encryptedData) throws IOException
    {
        if (privateKey == null || privateKey.length == 0)
        {
            return null;
        }

        if (encryptedData == null || encryptedData.length == 0)
        {
            return null;
        }
        //加密字节数组转换为十六进制的字符串 长度变为encryptedData.length * 2
        String data = Util.byteToHex(encryptedData);
        /***分解加密字串
         * &#xff08;C1 = C1标志位2位 + C1实体部分128位 = 130&#xff09;
         * &#xff08;C3 = C3实体部分64位  = 64&#xff09;
         * &#xff08;C2 = encryptedData.length * 2 - C1长度  - C2长度&#xff09;
         */
        byte[] c1Bytes = Util.hexToByte(data.substring(0,130));
        int c2Len = encryptedData.length - 97;
        byte[] c2 = Util.hexToByte(data.substring(130,130 + 2 * c2Len));
        byte[] c3 = Util.hexToByte(data.substring(130 + 2 * c2Len,194 + 2 * c2Len));

        SM2 sm2 = SM2.Instance();
        BigInteger userD = new BigInteger(1, privateKey);

        //通过C1实体字节来生成ECPoint
        ECPoint c1 = sm2.ecc_curve.decodePoint(c1Bytes);
        Cipher cipher = new Cipher();
        cipher.Init_dec(userD, c1);
        cipher.Decrypt(c2);
        cipher.Dofinal(c3);

        //返回解密结果
        return c2;
    }

    /**
     * 数据加密
     * @param data
     * @return
     */
    public static SMData SM2Encrypt(String data){
        SMData smData=new SMData();
        // 获取公钥私钥对
        SM2KeyPair sm2KeyPair = SM2Utils.generateKeyPair();
        // 获取公钥和私钥
        String publickey=sm2KeyPair.getPublicKey();
        String privatekey=sm2KeyPair.getPrivateKey();
        try {
            String encrypt = SM2Utils.encrypt(Util.hexToByte(publickey), data.getBytes("utf-8"));
            smData.setData(encrypt);
            smData.setSm2KeyPair(sm2KeyPair);
            return smData;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return smData;
    }

    /**
     * 数据解密
     * @param encryptData 加密后的数据
     * @param privatekey 私钥
     * @return
     */
    public static String SM2Decrypt(String encryptData,String privatekey){
        // 获取公钥私钥对
        //SM2KeyPair sm2KeyPair = SM2Utils.generateKeyPair();
        try {
            // 将加密后的信息解密;私钥和加密后的数据的字节码对象需要用util里的hexToByte方法
            byte[] decrypt = SM2Utils.decrypt(Util.hexToByte(privatekey), Util.hexToByte(encryptData));
            // 将字节数组转为字符串
            String newInfo=new String(decrypt,"utf-8");
            return newInfo;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "";
    }
}
